/**
 * @name renderer
 * @author Sowmya Balasubramanian, Aaron Hong, David Robertson
 */

var iconRouter = new GIcon();
iconRouter.image = 'markers/routerIcon.png';
iconRouter.shadow = 'markers/routerIcon_shadow.png';
iconRouter.iconSize = new GSize(23,23);
iconRouter.shadowSize = new GSize(23, 23);
iconRouter.iconAnchor = new GPoint(11, 11);
iconRouter.infoWindowAnchor = new GPoint(15, 1);

var iconHub = new GIcon();
iconHub.image = 'markers/hubIcon.png';
iconHub.shadow = 'markers/hubIcon_shadow.png';
iconHub.iconSize = new GSize(25,30);
iconHub.shadowSize = new GSize(30, 30);
iconHub.iconAnchor = new GPoint(12, 15);
iconHub.infoWindowAnchor = new GPoint(15, 1);

var iconSite = new GIcon();
iconSite.image = 'markers/siteIcon.png';
iconSite.iconSize = new GSize(23,23);
iconSite.iconAnchor = new GPoint(12, 15);
iconSite.infoWindowAnchor = new GPoint(15, 1);

var iconSiteAggr = new GIcon();
iconSiteAggr.image = 'markers/siteAggr.png';
iconSiteAggr.iconSize = new GSize(25,30);
iconSiteAggr.iconAnchor = new GPoint(12, 15);
iconSiteAggr.infoWindowAnchor = new GPoint(15, 1);

var iconPeer = new GIcon();
iconPeer.image = 'markers/peerIcon.png';
iconPeer.iconSize = new GSize(23,23);
iconPeer.iconAnchor = new GPoint(12, 15);
iconPeer.infoWindowAnchor = new GPoint(15, 1);

var iconPeerAggr = new GIcon();
iconPeerAggr.image = 'markers/peerAggr.png';
iconPeerAggr.iconSize = new GSize(25,30);
iconPeerAggr.iconAnchor = new GPoint(12, 15);
iconPeerAggr.infoWindowAnchor = new GPoint(15, 1);

var iconSiteRouter = new GIcon();
iconSiteRouter.image = 'markers/routerSiteAggr.png';
iconSiteRouter.iconSize = new GSize(25,30);
iconSiteRouter.iconAnchor = new GPoint(12, 15);
iconSiteRouter.infoWindowAnchor = new GPoint(15, 1);

var iconInvisible = new GIcon();
iconInvisible.image = 'markers/routerIcon.png';
iconInvisible.shadow = 'markers/hubIcon_shadow.png';
iconInvisible.iconSize = new GSize(0,0);
iconInvisible.shadowSize = new GSize(0, 0);
iconInvisible.iconAnchor = new GPoint(12, 15);
iconInvisible.infoWindowAnchor = new GPoint(15, 1);

var iconTypes = [];
iconTypes["hub"] = iconHub;
iconTypes["router"] = iconRouter;
iconTypes["site"] = iconSite;
iconTypes["siteAggr"] = iconSiteAggr;
iconTypes["peer"] = iconPeer;
iconTypes["peerAggr"] = iconPeerAggr;
iconTypes["siteRouterAggr"] = iconSiteRouter;
iconTypes["invisibleMarker"]=iconInvisible;

function RendererParams() {
    this.markersOnMap = new Object();
    this.polylineEncoder = new PolylineEncoder();
    this.linksOnMap = new Object();
    this.arrowsOnMap = new Object();
    this.prevColorsOnMap = new Object();
    this.logoScreenOverlay = undefined;
    this.copyScreenOverlay = undefined;
    this.currentLabel = undefined;
    this.oscarmarker = undefined;
}

// for Javascript version
function initializeRender(demo) {
    var center;
    // create map var here
    //var opts = new GMapOptions({size: new GSize(1024,1024)});
    if (demo == "globe") {
        wm.renderer.map = new GMap2(document.getElementById("map_canvas"),{size: new GSize(2048,1024)});
        center = new GLatLng(20.0, -89.0);
        wm.renderer.map.setCenter(center, 3); //for wm.weathermap.lod = 0
    } else {
        center = new GLatLng(38.396783299210966, -98.228515625);
        wm.renderer.map = new GMap2(document.getElementById("map_canvas"));
        wm.renderer.map.setCenter(center, 4); //for wm.weathermap.lod = 0
    }
    wm.renderer.map.setUIToDefault();
    wm.renderer.map.setMapType(G_PHYSICAL_MAP);

    wm.renderer.markersOnMap = new Object();
    wm.renderer.linksOnMap = new Object();
    wm.renderer.arrowsOnMap = new Object();
    wm.renderer.prevColorsOnMap = new Object();

    // from http://econym.org.uk/gmap/example_range.htm
    var mt = wm.renderer.map.getMapTypes();
    // Overwrite the getMinimumResolution() method to avoid useless zoom levels
    for (var i=0; i < mt.length; i++) {
        mt[i].getMinimumResolution = function() {return 2;};
    }
    // This is the only event listener that actually needs to be set on the map.
    // FIXME is this breaking any abstraction barriers?
    var zoomListener = GEvent.addListener(wm.renderer.map, "zoomend", function(oldLevel, newLevel) {
        determineLevelBasedOnZoom(newLevel);
    });
}

function clearOverlays() {
    if (wm.weathermap.flash) {
        getFlexApp('weathermap').clearMap();
        return;
    }
    wm.renderer.map.clearOverlays();
    wm.renderer.markersOnMap = new Object();
    wm.renderer.linksOnMap = new Object();
    wm.renderer.arrowsOnMap = new Object();
    wm.renderer.prevColorsOnMap = new Object();
}

function setMapBG(lvValue) {
    if (wm.weathermap.flash) {
        console.log("setMapBG.start");
        getFlexApp('weathermap').setMapBG(lvValue);
        console.log("setMapBG.finish");
        return;
    }
}

/**
 * This function places the nodes on the map. An array of markers is passed as parameter.
 * (for now it takes the array of markers and plots. Can be modified as per requirement)
 */
function drawNodes() {
    // delay drawing the markers a bit
    if (wm.weathermap.flash) {
        setTimeout("getFlexApp('weathermap').drawNodes();", 250);
        return;
    }
    for (var nodeName in wm.renderer.markersOnMap) {
        wm.renderer.map.addOverlay(wm.renderer.markersOnMap[nodeName]);
    }
}

/**
 * This function draws the links on the map.
 */
function drawLinks() {

    if (wm.weathermap.flash) {
        getFlexApp('weathermap').drawLinks();
        return;
    }
    for (var linkName in wm.renderer.linksOnMap) {
        // console.log("drawing: "+linkName);
        wm.renderer.map.addOverlay(wm.renderer.linksOnMap[linkName]);

        //draw arrows
        wm.renderer.arrowsOnMap[linkName] = createArrowOnPolyline(wm.renderer.linksOnMap[linkName]);
        wm.renderer.map.addOverlay(wm.renderer.arrowsOnMap[linkName]);
    }
}

function drawCopyrightInfo() {
    wm.renderer.map.checkResize();
    // set up logo
    if (wm.renderer.logoScreenOverlay) {
        wm.renderer.map.removeOverlay(wm.renderer.logoScreenOverlay);
    }
    if (wm.renderer.copyScreenOverlay) {
        wm.renderer.map.removeOverlay(wm.renderer.copyScreenOverlay);
    }
    var size = wm.renderer.map.getSize();
    var logoPctX = 1.0 - (107.0/size.width);
    var logoPctY = 1.0 - (80.0/size.height);
    // set up logo: absolute positioning doesn't work
    wm.renderer.logoScreenOverlay = new GScreenOverlay("markers/esnetLogo.png",
            new GScreenPoint(logoPctX, logoPctY, 'fraction', 'fraction'),
            new GScreenPoint(0, 0),
            new GScreenSize(60, 50));
    wm.renderer.map.addOverlay(wm.renderer.logoScreenOverlay);
    var copyPctX = 1.0 - (144.0/size.width);
    var copyPctY = 1.0 - (100.0/size.height);
    // set up copyright the kludgey way
    wm.renderer.copyScreenOverlay = new GScreenOverlay("markers/copyright.png",
            new GScreenPoint(copyPctX, copyPctY, 'fraction', 'fraction'),
            new GScreenPoint(0, 0),
            new GScreenSize(142, 23));
    wm.renderer.map.addOverlay(wm.renderer.copyScreenOverlay);
}

/**
 * This function redraws the copyright information (called when browser is
 * resized).
 */
function rendererResize() {
    if (wm.weathermap.flash) {
        getFlexApp('weathermap').drawCopyrightInfo();
    } else {
        drawCopyrightInfo();
    }
}

/* use get color to get line color
   use getlinewidth to get the line width
*/
function updateLinksOnMap(connName,capacity,utilization) {
    if (wm.weathermap.flash) {
        getFlexApp('weathermap').updateLinksOnMap(connName,capacity,utilization,
                                                  wm.metrics.utilizationType);
        return;
    }
    if (!wm.renderer.linksOnMap[connName]) {
        return;
    }
    // just check change in utilization for now
    var color = getLineColor(utilization);
    if (wm.renderer.prevColorsOnMap[connName] && (wm.renderer.prevColorsOnMap[connName] == color)) {
        return;
    }
    wm.renderer.prevColorsOnMap[connName] = color;
    var width = getLineWidth(capacity);
    var style = {"color":color,"weight":width,"opacity":color};
    wm.renderer.linksOnMap[connName].setStrokeStyle(style);
}

/////////////////////////////////////////////////////////////////////////////////
// Polyline functions
/////////////////////////////////////////////////////////////////////////////////

function createLink(linkName, to, from, index, cap) {
    if (wm.weathermap.flash) {
        getFlexApp('weathermap').createPolyline(linkName, from.lat(), from.lng(), to.lat(), to.lng(), index, cap);
        return;
    }
    var width = getLineWidth(cap);
    var colors = new Object();
    colors["in"] = "000000";
    colors["out"] = "000000";

    var offset = getLngOffset(from.lng(), to.lng());
    var adjPoint;
    // kludge for SC09
    if (linkName.indexOf("SC09") != -1) {
        if (wm.weathermap.demoMode == "globe") {
            adjPoint = new GLatLng(to.lat() - 5.0, to.lng() - 9.0);
        } else if (wm.renderer.map.getZoom() < 4) {
            adjPoint = new GLatLng(to.lat() - 3.0, to.lng() + 1.0);
        } else if (wm.renderer.map.getZoom() == 4) {
            adjPoint = new GLatLng(to.lat() - 1.5, to.lng() + 1.0);
        } else {
            // only takes effect when level of detail changes
            adjPoint = new GLatLng(to.lat(), to.lng());
        }
    } else {
        adjPoint = new GLatLng(to.lat(), to.lng());
    }
    var newFrom = new GLatLng(from.lat(), adjustLngTo(from.lng(), offset));
    var newTo = new GLatLng(adjPoint.lat(), adjustLngTo(adjPoint.lng(), offset));
    var polyline_in  = wm.renderer.polylineEncoder.dpEncodeToGPolyline(createMapCurve(newFrom, newTo, index, "second-half"), colors["in"], width, 0.6, offset);
    var polyline_out = wm.renderer.polylineEncoder.dpEncodeToGPolyline(createMapCurve(newTo, newFrom, index, "second-half"), colors["out"], width, 0.6, offset);
    wm.renderer.linksOnMap[linkName+"_in"]  = polyline_in;
    wm.renderer.linksOnMap[linkName+"_out"] = polyline_out;
}

/*
 * Find if source and destination cross the international date line, and
 * calculates offset for from and to so all in one hemisphere.  Probably a
 * more elegant solution.
 */
function getLngOffset(from, to) {
    var offset = 0.0;
    var fromDist = 180.0 - Math.abs(from);
    var toDist  = 180.0 - Math.abs(to);
    if ((fromDist + toDist) < 180.0) {
        if ((from < 0.0) && (to > 0.0)) {
            offset = 181.0 - to;
        } else if ((to < 0.0) && (from > 0.0)) {
            offset = 181.0 - from;
        }
    }
    return offset;
}

/*
 * Adds to a longitude, converting to other hemisphere if necessary.
 */
function adjustLngTo(lng, offset) {
    var newLng = lng;
    if (offset != 0.0) {
        newLng += offset;
        if (newLng > 180.0) {
            newLng = -180.0 + (newLng - 180.0);
        }
    }
    return newLng;
}

/*
 * Subtracts from a longitude, converting to other hemisphere if necessary.
 */
function adjustLngFrom(lng, offset) {
    var newLng = lng;
    if (offset != 0.0) {
        newLng -= offset;
        if (newLng < -180.0) {
            newLng = newLng + 360;
        }
    }
    return newLng;
}

/////////////////////////////////////////////////////////////////////////////////
// Curve Function
/////////////////////////////////////////////////////////////////////////////////

/*
 * Draw a curve between two nodes.
 *
 * @param   to      The ending point of the curve
 * @param   from    The starting point of the curve
 * @param   index   Integer to distinguish between curves between the same points
 * @param inout     0 if the "in" part, 1 if "out"
 * @return          GLatLng Array of points on the curve.
 *
 * FIXME get too choose the number of divisions?
 */
function createMapCurve(to, from, index, segment){
    var seg = segment || "whole";
    var p0 = new Vector2d(to.lng(), to.lat());
    var p3 = new Vector2d(from.lng(), from.lat());

    // horrible kludge for SC09 to make room for marker and have
    // edge from Sunnyvale show up
    var vert = from.lng() - to.lng();
    var angle;
    if (Math.abs(vert) > 5.0) {
        angle = Math.PI * (1.5 + .45 * index) / 36;
    } else {
        index++;
        angle = -Math.PI * (1.5 + .45 * index) / 36;
    }
    // end of kludge
    angle = Math.PI * (.5 + .5 * index)/6;
    var magnitudeScale = (.5 + .5 * index)/6;
    var controlPoints = getControlPoints(p0, p3, magnitudeScale, angle);
    var c1 = controlPoints[0];
    var c2 = controlPoints[1];

    var curveXY = getBezier(p0, c1, c2, p3, 3, seg);
    var curveLL = new Array();
    for(var i = 0; i < curveXY.length; i++){
        curveLL.push(new GLatLng(curveXY[i].y, curveXY[i].x));
    }
    return curveLL;
}

/////////////////////////////////////////////////////////////////////////////////
// Marker Functions
/////////////////////////////////////////////////////////////////////////////////

/**
 * Function to create a labeled marker at the specified location on the map with info card.
 *
 * @param   point   Coordinates of the location where the marker is to be placed
 * @param   type    A name that indicates which icon is to be used
 * @param   label   Text for label to be displayed near the marker
 * @param   info    Text to be displayed inside the info box
*/
function createMarker(point, type, label, info) {
    if (wm.weathermap.flash) {
        getFlexApp('weathermap').createMarker(point.lat(), point.lng(), type, label, info);
        return;
    }
    var adjPoint;
    // kludge for SC09
    if (label == "SC09") {
         if (wm.renderer.map.getZoom() < 4) {
            adjPoint = new GLatLng(point.lat() - 3.0, point.lng() + 10.0);
         } else if (wm.renderer.map.getZoom() == 4) {
            adjPoint = new GLatLng(point.lat() - 1.5, point.lng() + 1.0);
         } else {
            adjPoint = new GLatLng(point.lat(), point.lng());
         }
    } else {
        adjPoint = new GLatLng(point.lat(), point.lng());
    }
    var showLabels = document.getElementById("labelsCheckbox").checked;
    // fudge factor needed; visualLength slightly off
    var xOffset = -visualLength(label)/2 + 3;
    var marker = new LabeledMarker(adjPoint, {icon: iconTypes[type], labelText: label, labelOffset: new GSize(xOffset, -27), labelVisibility: showLabels});
    var html = "<b>" + label + "</b> <br/>" + info;
    var level = wm.weathermap.lod;
    var intervalId;
    var onDoubleClick = function() {
        // zooms in to level 10 if alt click at lower resolution
        // zooms out to level 4 if at 10 or above
        clearOverlays();
        if (wm.renderer.map.getZoom() < 10) {
            wm.renderer.map.setCenter(point, 10, GMapType.G_PHYSICAL_MAP);
        } else {
            wm.renderer.map.setCenter(point, 4, GMapType.G_PHYSICAL_MAP);
        }
    };
    var onSingleClick = function() {
        // opening info window stops playback for good
        //if (!wm.metrics.playbackOn) {
            var table = getInfoCard(label, 1);
            var tab = new GInfoWindowTab(label, table);
            var tabs = new Array();
            tabs.push(tab);
            try {
                marker.openInfoWindowTabsHtml(tabs);
            } catch (e) {
                console.log("caught exception");
            }
        //}
    };

    // double click handling adapted from
    // http://www.actionscript.org/resources/articles/566/1/Doubleclick-Event-for-MovieClip/Page1.html
    var singleClickHandler = function() {
        if (intervalId) {
            onSingleClick();
            clearInterval(intervalId);
            intervalId = 0;
        }
    };
    GEvent.addListener(marker, 'click', function() {
        if (intervalId) {
            onDoubleClick();
            clearInterval(intervalId);
            intervalId = 0;
        } else {
            intervalId = setInterval(singleClickHandler, 200);
        }
    });
    wm.renderer.markersOnMap[label] = marker;
}

 /**
  * Turn off the labels on the marker.
  *
  * @param  showLabels Boolean value that indicates whether to show the labels or not
  */
function labelVisibility(showLabels) {
    if (wm.weathermap.flash) {
        getFlexApp('weathermap').setLabelVisibility(showLabels);
        return;
    }
    for (var nodeName in wm.renderer.markersOnMap) {
        wm.renderer.markersOnMap[nodeName].setLabelVisibility(showLabels);
    }
}

function updateInfoCard() {
    if (wm.weathermap.flash) {
        if (wm.renderer.currentLabel) {
            //getFlexApp('weathermap').updateInfoCard(getInfoCard(wm.renderer.currentLabel, 1));
        }
        return;
    }
    if (wm.renderer.map.getInfoWindow().isHidden()) {
        return;
    } else {
        var node = getInfoCard(wm.renderer.currentLabel, 1);
        var tab = new GInfoWindowTab(wm.renderer.currentLabel, node);
        var tabs = new Array();
        tabs.push(tab);
        try {
            wm.renderer.map.updateInfoWindow(tabs);
        } catch (e) {
            console.log("caught exception");
        }
    }
}

function getInfoCard(name, flex) {
    if (!wm.metrics.metricsData) {
        return;
    }
    wm.renderer.currentLabel = name;
    var show = [wm.weathermap.showSdn, wm.weathermap.showIp, wm.weathermap.showPeers];
    var networks = ["SDN", "IP", "PEER"];
    console.log("name " +  name);
    console.log("lod " + wm.weathermap.lod);
    var table="";
    var flextable = new Array();

    if (!wm.weathermap.flash) {
        var utilType;
        if (wm.metrics.utilizationType == "percent") {
            utilType = "%";
        } else {
            utilType = "Mbps";
        }
        table = "<table border='1' cellspacing='2' class='metrics'><tr><th>Interface</th>" +
        "<th>Capacity (Mbps)</th>" +
        "<th>In-bound Utilization (" + utilType +
        ")</th><th>Out-bound Utilization (" + utilType +
        ")</th></tr>";
    }

    for (var i = 0; i < networks.length; i++) {
        if (!show[i]) {
            continue;
        }
        var network = networks[i];
        for (var conStr in wm.topology.topologyData[network][wm.weathermap.lod].connections) {
            var connection = wm.topology.topologyData[network][wm.weathermap.lod].connections[conStr];
            var linkName = undefined;

            if (connection.src == name) {
                linkName = conStr;
            } else if (connection.dst == name) {
                linkName = connection.reverse;
            }
            if (linkName != undefined) {
                var inMetric = wm.metrics.metricsData[linkName]["in"];
                var outMetric = wm.metrics.metricsData[linkName]["out"];
                var inUtil;
                var outUtil;
                //change if network utilization hits 100%
                if (wm.metrics.utilizationType == "percent") {
                    inUtil = Math.round(inMetric.utilization*10000)/100;
                    outUtil =  Math.round(outMetric.utilization*10000)/100;
                    if (inUtil < 0.0) {
                        inUtil = "N.A.";
                    }
                    if (outUtil < 0.0) {
                        outUtil = "N.A.";
                    }
                } else {
                    inUtil = Math.round(inMetric.utilization);
                    outUtil =  Math.round(outMetric.utilization);
                }
                // inbound and outbound capacity are the same
                var capacity = inMetric.capacity;
                if (wm.weathermap.flash) {
                    var obj = new UtilObj(linkName,inUtil,capacity,outUtil);
                    flextable.push(obj);
                } else {
                    var metr = "<td class='number'>" + capacity + "</td>" +
                                "<td class='number'>" + inUtil + "</td>" +
                                "<td class='number'>" + outUtil + "</td>";
                    table += "<tr><td>" + linkName + "</td>" + metr + "</tr>";
                }
            }
        }
    }
    table += "</table>"
    if (!wm.weathermap.flash) {
        return table;
    } else {
        return flextable;
    }
}

/**
 * Find the visual length of text in pixels. Used for centering text.
 *
 * @param   s   String to be evaluated
 */
function visualLength(s) {
    if (document.getElementById) {
        var rulerSpan = document.getElementById('ruler');
        rulerSpan.innerHTML = s;
        var width = rulerSpan.offsetWidth;
        rulerSpan.innerHTML = "";
        return width;
    }
}

/////////////////////////////////////////////////////////////////////////////////
// Arrow Functions
/////////////////////////////////////////////////////////////////////////////////

/**
 * Draw arrow on the middle of the curve. If the size of the link is too
 * small, smaller arrow head will be used.
 *
 * @param   curveLL GLatLong that describes the curve
 * @param   opacity The opacity of the drawn arrow
 * @param   color   The color of the arrow in 3-byte hex
 */
function createArrowOnPolyline(polyline, opacity, color) {
    var opac = opacity || 1;
    var colour = color || "#FF6633";
    var size = 1;
    var difLng = polyline.getVertex(polyline.getVertexCount()-1).x-polyline.getVertex(0).x;
    var difLat = polyline.getVertex(polyline.getVertexCount()-1).y-polyline.getVertex(0).y;
    var magSquared = difLng*difLng + difLat*difLat;
    //40 is roughly in between 4^2+4^2 and 5^2+5^2
    if (magSquared < 40) {
        size=2;
    }
    var middle = Math.floor(polyline.getVertexCount()/2);
    var bear = bearing(polyline.getVertex(middle), polyline.getVertex(middle-1));
    if (isNaN(bear)) {
        console.warn("Warning: Bearing is NaN");
        bear = 90;
    }
    var tooltipText = "capacity"
    //BDCCArrow(point, rotation, color, opacity, tooltip)
    //console.log(polyline);
    var arrow = new BDCCArrow(polyline.getVertex(middle-1), bear, colour, opac, tooltipText, size);
    return arrow;
}

/**
 * Find the bearing of a line based on latitude and longitude coordinates.
 *
 * @param   fromLL  The starting point of the line as a GLatLng
 * @param   toLL    The ending point of the line as a GLatLng
 * @param   zoom    The zoom the user is currently at (may not be necessary)
 *
 * FIXME See if the zoom actually matters.
 */
function bearing(fromLL, toLL) {
    var degreesPerRadian = 180.0 / Math.PI;
    var currentProjection = G_NORMAL_MAP.getProjection();
    var highestZoom = wm.renderer.map.getCurrentMapType().getMaximumResolution();
    // The second parameter is the zoom level (get it from the highest zoom level)
    var from = currentProjection.fromLatLngToPixel(fromLL, highestZoom);
    var to = currentProjection.fromLatLngToPixel(toLL, highestZoom);

    var x = to.x - from.x;
    var y = to.y - from.y;
    if ((x == 0) && (y == 0)) {
        return 90;  // arbitrary: to and from are at same point
    }
    var mag = Math.sqrt(x*x + y*y);

    // Compute the angle.
    var angle = Math.acos(-y/mag);
    if ( x < 0.0) {
        angle  = Math.PI * 2.0 - angle;
    }
    // And convert result to degrees.
    angle = angle * degreesPerRadian;
    return angle;
}

/**
 * Moving the tip of the arrow back along a line.
 * Since it's on a curve, it may no longer be necessary.
 */
function moveHeadBack(to, from, amount) {
    var dirLng = from.lng() - to.lng();
    var dirLat = from.lat() - to.lat();
    var mag = Math.sqrt(dirLng*dirLng + dirLat*dirLat);
    if (mag == 0) {
        //line has no length
        return to;
    }
    dirLng /= mag;
    dirLat /= mag;
    //tip of arrow
    var tipLng = (to.lng() + dirLng * amount);
    var tipLat = (to.lat() + dirLat * amount);
    return new GLatLng(tipLat, tipLng);
}

////////////////////////////////////////
//Line color and line width functions///
///////////////////////////////////////

function getLineWidth(cap) {
    var width = 1;
    if (cap>0 && cap<999) {
        width=1.5;
    } else if(cap>999 && cap<9999) {
        width=2;
    } else if(cap>9999 && cap<19999) {
        width=3;
    } else if(cap>19999 && cap<39999) {
        width=5;
    } else {
        width=6;
    }
    return width;
}

function getLineColor(utilization) {
    if (wm.metrics.utilizationType == "percent") {
        if (utilization > 1.0) {
            console.warn("utilization data error: " + utilization);
        }
        // only happens where percent reserved is not applicable
        if (utilization < 0.0) {
            return "444444";
        } else if (utilization < 0.05) {
            return "0066CC";
        } else if (utilization < 0.10) {
            return "009900";
        } else if (utilization < 0.20) {
            return "99FF00";
        } else if (utilization < 0.30) {
            return "FFFF00";
        } else if (utilization < 0.40) {
            return "FF9933";
        } else if (utilization < 0.50) {
            return "CC3333";
        } else {
            return "990033";
        }
    // Mbps
    } else {
       if (utilization < 100) {
            return "0066CC";
        } else if (utilization < 250) {
            return "009900";
        } else if (utilization < 500) {
            return "99FF00";
        } else if (utilization < 1000) {
            return "FFFF00";
        } else if (utilization < 5000) {
            return "FF9933";
        } else if (utilization < 10000) {
            return "CC3333";
        } else {
            return "990033";
        }
   }
}


//////////////////////////////////////////////////////
//      OSCARS circuit functions                    //
/////////////////////////////////////////////////////

function createPathDS(nodeLat,nodeLong,numOfHops,bandwidth,pathname) {
    var coord = new Array(numOfHops);
    var num = numOfHops;
    var color = "660099"; //purple
    var width = 10;

    if (wm.weathermap.flash==true) {
        getFlexApp('weathermap').createPathDS(nodeLat,nodeLong,numOfHops,bandwidth,pathname);
        return;
    }
    for (var i=0; i<num; i++) {
       coord[i] = new GLatLng(nodeLat[i],nodeLong[i]);
       if (num == 1) {
            //num=4;
            coord = new Array(numOfHops+3);
            coord[0] = new GLatLng(nodeLat[0],nodeLong[0]);
            coord[1]=new GLatLng(nodeLat[1],nodeLong[1]);
            coord[2]=new GLatLng(nodeLat[2],nodeLong[2]);
            coord[3]=new GLatLng(nodeLat[3],nodeLong[3]);

       }
    }
    if (coord != undefined) {
        wm.path.pathToAdd = wm.renderer.polylineEncoder.dpEncodeToGPolyline(
                              coord, color, getOSCARSLineWidth(bandwidth), 0.9);
        wm.path.pathName=pathname;
        wm.path.pathNameCoord = coord[Math.round(numOfHops/2)];
    }
}

function drawPath() {

    if (wm.weathermap.flash==true) {
        getFlexApp('weathermap').drawPath();
        return;
    }
    if (wm.path.pathToRemove != undefined) {
        wm.renderer.map.removeOverlay(wm.path.pathToRemove);
        wm.path.pathToRemove = undefined;
        wm.renderer.map.removeOverlay(wm.path.oscarmarker);
    }
    if (wm.path.pathToAdd != undefined) {
        wm.renderer.map.addOverlay(wm.path.pathToAdd);
        var type= "invisibleMarker";
        var info = "OSCAR CIRCUIT"
        wm.path.pathNameCoord = new GLatLng(45.77,-110.40)
        wm.path.oscarmarker =
            new LabeledMarker(wm.path.pathNameCoord, {icon: iconTypes[type],
                    labelText: wm.path.pathName,
                    labelOffset: new GSize(27, -27)});
        wm.renderer.map.addOverlay(wm.path.oscarmarker);
        wm.path.pathOnMap = wm.path.pathToAdd;
        wm.path.pathToRemove = wm.path.pathToAdd;
        wm.path.pathToAdd = undefined;
    }
}

function getOSCARSLineWidth(cap) {
    var width =1;
    if(cap>0 && cap<=500)
        width=5;
    else if(cap>500 && cap<=1000)
        width =8;
    else if(cap>1000 && cap<=5000)
        width=12;
    else
        width =14;

    return width;
}

function getCoord(l,dir) {
     getFlexApp('weathermap').getCoord(l,dir);
}

function UtilObj(intfName, inUtil, capacity, outUtil) {
    this["Ifce"] = intfName;
    this["Link Capacity (Mbps)"] = capacity;
    if (wm.metrics.utilizationType == "percent") {
        this["Utilization In (%)"] = inUtil;
    } else {
        this["Utilization In (Mbps)"] = inUtil;
    }
    if (wm.metrics.utilizationType == "percent") {
        this["Utilization Out (%)"] = outUtil;
    } else {
        this["Utilization Out (Mbps)"] = outUtil;
    }
}
